package com.hex.tcpproxy.util;

import com.hex.tcpproxy.test.TimeClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author: [wujie]
 * @createTime: [2019/10/7 17:08]
 * @description:
 */
public class ProxyClient implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ProxyClient.class);

    private String host;
    private Integer port;
    private ChannelInboundHandlerAdapter handlerAdapter;
    private EventLoopGroup group;

    public ProxyClient(String host, int port, ChannelInboundHandlerAdapter handlerAdapter) {
        this.host = host;
        this.port = port;
        this.handlerAdapter = handlerAdapter;
    }

    @Override
    public void run() {
        connect();
    }

    public void connect() {
        /**配置客户端 NIO 线程组/池*/
        group = new NioEventLoopGroup();
        try {
            /**Bootstrap 与 ServerBootstrap 都继承(extends)于 AbstractBootstrap
             * 创建客户端辅助启动类,并对其配置,与服务器稍微不同，这里的 Channel 设置为 NioSocketChannel
             * 然后为其添加 Handler，这里直接使用匿名内部类，实现 initChannel 方法
             * 作用是当创建 NioSocketChannel 成功后，在进行初始化时,将它的ChannelHandler设置到ChannelPipeline中，用于处理网络I/O事件*/
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(handlerAdapter);
                        }
                    });

            /**connect：发起异步连接操作，调用同步方法 sync 等待连接成功*/
            ChannelFuture channelFuture = b.connect(host, port).sync();
            logger.info(Thread.currentThread().getName() + ",客户端发起异步连接..........");

            /**等待客户端链路关闭*/
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            /**优雅退出，释放NIO线程组*/
            group.shutdownGracefully();
        }
    }

    public void close() {
        group.shutdownGracefully();
    }
}
